export class Vector2 {

    x!: number;
    y!: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    add(v: Vector2) {
        return new Vector2(this.x + v.x, this.y + v.y);
    }

    subtract(v: Vector2) {
        return new Vector2(this.x - v.x, this.y - v.y);
    }

    multiply(n: number) {
        return new Vector2(this.x * n, this.y * n);
    }

    divide(n: number) {
        return new Vector2(this.x / n, this.y / n);
    }

    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    unitVector() {
        const length = 1 / this.length();
        return new Vector2(this.x * length, this.y * length);
    }

    inverseVector() {
        return new Vector2(-this.x, -this.y);
    }

    crossMultiply(v: Vector2): number {
        return this.x * v.y - this.y * v.x;
    }

    dotMultiply(v: Vector2): number {
        return this.x * v.x + this.y * v.y;
    }

}

export class Vector2Util {

    constructor() {

    }

    /**
     * get v1 to v2 cos value
     * @param v1 vertor one
     * @param v2 vertor two
     * @returns v1 to v2 cos
     */
    public static cosVector(v1: Vector2, v2: Vector2): number {
        return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length());
    }

    /**
     * get radian or angle
     * @param v1 vector one
     * @param v2 vector two
     * @param isRadian radian or angle
     * @returns radian or angle
     */
    public static angleVector(v1: Vector2, v2: Vector2, isRadian = true) {
        const type = isRadian ? 1 : 180 / Math.PI;
        return Math.acos(Vector2Util.cosVector(v1, v2)) * type;
    }

    public static crossMultiply(v1: Vector2, v2: Vector2): number {
        return v1.x * v2.y - v1.y * v2.x;
    }

    /**
     * get reflect vector
     * @param v1 input vector
     * @param vNormal vector normal line
     * @returns reflect vector line
     */
    public static getReflected(v1: Vector2, vNormal: Vector2): Vector2 {
        // v1 - 2 * v1.dotMultiply(vNormal) * vNormal
        const v1Unit = v1.unitVector();
        const normalUnit = vNormal.unitVector();
        return v1Unit.subtract(normalUnit.multiply(2 * v1Unit.dotMultiply(normalUnit))).multiply(v1.length());
    }
}
